//////////////////////////////////////////////////////////////////////////////////////////
/////
/// This is part of a collection of libraries developed by Asaf Shelly
/// More about Asaf Shelly: http://Asaf.Shelly.co.il
/// More about the libraries: http://AsyncOp.com
///
/// You are permitted to use, copy, publish, execute and redistribute
/// this code and library free of charge for the duration of the copyright 
//
//////////////////////////////////////////////////////////////////////////////////////////
///// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
///// DEALINGS IN THE SOFTWARE
//////////////////////////////////////////////////////////////////////////////////////////
/////
/// For more details and an explicit legal permission you can contact me
/// directly:
/// Asaf Shelly
/// OpenSource@Shelly.co.il
/// http://AsyncOp.com
/// http://Asaf.Shelly.co.il
///
/// This code has been under development for over ten years and is still
/// updated occasionally.
/// It is recommended that you go online to find updates and fixed.
/// It is also recommended that you add a link in your code that is using
/// this or part of this source for future reference.
/// 
/// If you have any bug fixes, known bugs, updates, extensions, and other
/// comments feel free to post to the website or contact me directly.
//

// Peripherals.cpp is the source file for the Peripherals.h header file, implementing communication with system peripherals.
// By Asaf Shelly
// 26-11-2003

 #include <Peripherals.h>


 SerialPort::SerialPort(int port): hPort(INVALID_HANDLE_VALUE)
  {
   commTimeOuts.ReadIntervalTimeout=1;
   commTimeOuts.ReadTotalTimeoutMultiplier=1;
   commTimeOuts.ReadTotalTimeoutConstant=1;
   commTimeOuts.WriteTotalTimeoutMultiplier=1;
   commTimeOuts.WriteTotalTimeoutConstant=1;
   memset(&portDcb,0,sizeof(portDcb)); portDcb.DCBlength=sizeof(portDcb);
   fileName<<"COM"<<port;
  }

 SerialPort::~SerialPort()
  {
   if (PE(this)) return;
   if (hPort!=INVALID_HANDLE_VALUE) { CloseHandle(hPort); hPort=INVALID_HANDLE_VALUE; }
  }

 DWORD __stdcall SerialPort::Open(int port)
  {
   if (PE(this)) return(ERROR_INVALID_HANDLE);
   if (-1==port)
    {
     if (!(fileName.Len())) return(ERROR_INVALID_NAME);
    }
    else { fileName="COM"; fileName<<port; }
   if (hPort!=INVALID_HANDLE_VALUE) { CloseHandle(hPort); hPort=INVALID_HANDLE_VALUE; }


//CREATEFILE CALLED
   if (INVALID_HANDLE_VALUE==(hPort=CreateFile(fileName.Str(),GENERIC_ALL,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0)))
    { return(GetLastError()); }


   if (!(SetCommTimeouts(hPort,&commTimeOuts)))
    { return(GetLastError()); }
   if (!(GetCommState(hPort,&portDcb)))
    { return(GetLastError()); }
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::Close()
  {
   if (PE(this)) return(ERROR_INVALID_HANDLE);
   if (hPort!=INVALID_HANDLE_VALUE) { CloseHandle(hPort); hPort=INVALID_HANDLE_VALUE; }
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::Write(char* pBuffer, int length)
  {
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)) return(ERROR_INVALID_HANDLE);
   if ((PE(pBuffer))||(!length)) return(ERROR_INVALID_USER_BUFFER);
   if (-1==length) length=strlen(pBuffer);
   if (!length) return(ERROR_INVALID_USER_BUFFER);
   DWORD dwWritten=0;

//WRITEFILE called
   if (!WriteFile(hPort,pBuffer,length,&dwWritten,NULL)) return(GetLastError());
   if (dwWritten<length) return(ERROR_CAN_NOT_COMPLETE);
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::Read(char* pBuffer, int length, DWORD *pdwRead)
  {   // NOTE pdwRead may be NULL.
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)) return(ERROR_INVALID_HANDLE);
   if ((PE(pBuffer))||(!length)) return(ERROR_INVALID_USER_BUFFER);

  //READFILE called
   if (!ReadFile(hPort,pBuffer,length,pdwRead,NULL)) return(GetLastError());
   return(ERROR_SUCCESS);
  }

 


 //USE following to setup link to board over virtual com port
 DWORD __stdcall SerialPort::SetBaudRate(int rate)
  {
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)) return(ERROR_INVALID_HANDLE);
   if (!(GetCommState(hPort,&portDcb))) { return(GetLastError()); }
   portDcb.BaudRate=rate;
   if (!(SetCommState(hPort,&portDcb))) { return(GetLastError()); }
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::SetDataBits(int bits)
  {
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)) return(ERROR_INVALID_HANDLE);
   if (!(GetCommState(hPort,&portDcb))) { return(GetLastError()); }
   portDcb.ByteSize=bits;
   if (!(SetCommState(hPort,&portDcb))) { return(GetLastError()); }
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::SetParity(int parity)
  {
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)) return(ERROR_INVALID_HANDLE);
   if (!(GetCommState(hPort,&portDcb))) { return(GetLastError()); }
   portDcb.Parity=parity;
   if (!(SetCommState(hPort,&portDcb))) { return(GetLastError()); }
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::SetStopBits(int bits)
  {
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)) return(ERROR_INVALID_HANDLE);
   if (!(GetCommState(hPort,&portDcb))) { return(GetLastError()); }
   portDcb.StopBits=bits;
   if (!(SetCommState(hPort,&portDcb))) { return(GetLastError()); }
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::SetFlowXonXoff(int flow)
  {
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)) return(ERROR_INVALID_HANDLE);
   if (!(GetCommState(hPort,&portDcb))) { return(GetLastError()); }
   portDcb.fOutX=flow;
   portDcb.fInX=flow;
   if (!(SetCommState(hPort,&portDcb))) { return(GetLastError()); }
   return(ERROR_SUCCESS);
  }

 DWORD __stdcall SerialPort::SetTimeouts(int sec)
  {
   if (PE(this)) return(ERROR_INVALID_HANDLE);
   //commTimeOuts.ReadIntervalTimeout=sec;
   //commTimeOuts.ReadTotalTimeoutMultiplier=sec;
   commTimeOuts.ReadTotalTimeoutConstant=sec;
   //commTimeOuts.WriteTotalTimeoutMultiplier=sec;
   commTimeOuts.WriteTotalTimeoutConstant=sec;
   if (hPort!=INVALID_HANDLE_VALUE)
    {
     if (!(SetCommTimeouts(hPort,&commTimeOuts))) { return(GetLastError()); }
    }
   return(ERROR_SUCCESS);
  }





 DWORD __stdcall SerialPort::CommError(DWORD& errCode)
  {
   if ((PE(this))||(INVALID_HANDLE_VALUE==hPort)||(RE(errCode))) return(ERROR_INVALID_HANDLE);
   if (!ClearCommError(hPort,&errCode,NULL)) return(GetLastError());
   return(ERROR_SUCCESS);
  }
